#include <iostream>
#include "Poco/Timer.h"
#include "Poco/Exception.h"
#include "Timer.h"

using namespace SystemTool;

namespace SystemTool
{
    class InnerTimerCallBack
    {
    public:
        void SetFunc(std::function<void(void *)> fFunc, void *pUserData)
        {
            m_fFunc = fFunc;
            m_pUserData = pUserData;
        }

        void OnTimer(Poco::Timer &t)
        {
            if (m_fFunc)
            {
                m_fFunc(m_pUserData);
            }
        }

    private:
        std::function<void(void *)> m_fFunc = nullptr;
        void *m_pUserData = nullptr;
    };
}

// Construct the timer with interval
Timer::Timer(long iPeriodInterval,long iDelayTimeAndStart)
{
    m_pTimer = new Poco::Timer(iDelayTimeAndStart, iPeriodInterval);
    m_pCallBack = new InnerTimerCallBack;
}

// Destruct the timer
Timer::~Timer()
{
    if(m_pCallBack)
    {
        delete (InnerTimerCallBack*)m_pCallBack;
        m_pCallBack = nullptr;
    }

    if(m_pTimer)
    {
        delete (Poco::Timer*)m_pTimer;
        m_pTimer = nullptr;
    }
}

// Start with callback func and priority
void Timer::Start(std::function<void(void*)> fFunc, void *pUserData, TimerPriority ePreority)
{
    if(m_pTimer)
    {
        try
        {
            ((InnerTimerCallBack *)m_pCallBack)->SetFunc(fFunc, pUserData);
            Poco::TimerCallback<InnerTimerCallBack> tc(*((InnerTimerCallBack *)m_pCallBack), &InnerTimerCallBack::OnTimer);
            ((Poco::Timer *)m_pTimer)->start(tc, (Poco::Thread::Priority)(int)ePreority);
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Stop the timer
void Timer::Stop()
{
    if(m_pTimer)
    {
        try
        {
            ((Poco::Timer *)m_pTimer)->stop();
        }
        catch (const Poco::Exception &e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Stop the timer inner callback func
void Timer::StopInCallBackFunc()
{
    if(m_pTimer)
    {
        try
        {
            ((Poco::Timer *)m_pTimer)->restart(0);
        }
        catch (const Poco::Exception &e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// How many cnt has beened skipped
long Timer::GetSkippedCnt() const
{
    if(m_pTimer)
    {
        return ((Poco::Timer *)m_pTimer)->skipped();
    }

    return 0;
}

// Get current start interval
long Timer::GetCurStartInterval() const
{
    if(m_pTimer)
    {
        return ((Poco::Timer *)m_pTimer)->getStartInterval();
    }
    
    return 0;
}

// Set start interval which will be effetived again before start()
void Timer::SetStartInterval(long iMs)
{
    if(m_pTimer)
    {
        try
        {
            ((Poco::Timer *)m_pTimer)->setStartInterval(iMs);
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Get current peroid interval
long Timer::GetCurPeroidInterval() const
{
    if(m_pTimer)
    {
        return ((Poco::Timer *)m_pTimer)->getPeriodicInterval();
    }
    
    return 0;
}

// Set peroid interval and it will be used by next peroid
void Timer::SetPeroidInterval(long iMs)
{
    if(m_pTimer)
    {
        try
        {
            ((Poco::Timer *)m_pTimer)->setPeriodicInterval(iMs);
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}
